/**
 * 
 * @Project le cOeur - Data Virtualization
 * @Date 08.12.2012
 * @Author Aebi Pascal, Kocher Marc
 * @School BFH-TI Biel, Bachelor Thesis
 *
 */

package main.framework;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.concurrent.ExecutorService;
import java.util.logging.Logger;

import main.framework.connection.Protocol;
import main.framework.exception.PortListenerException;

/**
 * This class represents a port listener which listens on the defined port and accepts connections.
 */
public class PortListener implements Runnable {

	private ExecutorService threadPool;
	private RequestHandler requestHandler;
	private ServerSocket serverSocket;
	private Status status;
	private Protocol protocol;
	private int port;
	private Logger logger;

	/**
	 * Creates a port listener.
	 * 
	 * @param protocol The protocol for which the port listener accepts connections.
	 * @param port The port number on which the port listener listens for connections.
	 * @param threadPool The thread pool which executes the worker threads.
	 * @param requestHandler The request handler which handles the requests.
	 */
	public PortListener(Protocol protocol, int port, ExecutorService threadPool, RequestHandler requestHandler) {
		this.protocol = protocol;
		this.port = port;
		this.threadPool = threadPool;
		this.requestHandler = requestHandler;
		this.logger = Logger.getLogger("SysLogger");
		this.status = Status.DISABLED;
	}
	
	@Override
	public void run() {
		while(this.status == Status.ENABLED){
			try {
				Socket socket = this.serverSocket.accept();
				this.threadPool.execute(new Worker(socket, this.requestHandler));
			} catch (SocketException e) {
				this.logger.warning(e.getMessage());
			} catch (IOException e) {
				this.logger.warning(e.getMessage());
			}
		}
	}

	/**
	 * Enables the port listener.
	 * 
	 * @throws PortListenerException If the port listener could not be enabled because it is already enabled.
	 */
	public void enable(ServerSocket serverSocket) throws PortListenerException {
		if(this.status == Status.DISABLED) {
			this.status = Status.ENABLED;
			this.serverSocket = serverSocket;
			this.logger.info("The port listener of port " + this.port + " (" + this.protocol + ") is enabled.");
		}
		else{
			throw new PortListenerException("The port listener is already enabled.");
		}
	}
	
	/**
	 * Disables the port listener.
	 * 
	 * @throws IOException If an I/O error occurs when closing the socket.
	 * @throws PortListenerException If the port listener could not be disabled because it is already disabled.
	 */
	public void disable() throws IOException, PortListenerException {
		if(this.status == Status.ENABLED) {
			this.status = Status.DISABLED;
			this.serverSocket.close();
			this.serverSocket = null;
			this.logger.info("The port listener of port " + this.port + " (" + this.protocol + ") is disabled.");
		}
		else{
			throw new PortListenerException("The port listener is already disabled.");
		}
	}
	
	/**
	 * Returns if the port listener is enabled or disabled. 
	 * 
	 * @return True if enabled, else false.
	 */
	public boolean isEnabled(){
		if(this.status == Status.ENABLED) {
			return true;
		}
		else{
			return false;
		}
	}
	
	/**
	 * Returns the port number to which the port listener is assigned.
	 * 
	 * @return The port number.
	 */
	public int getPort() {
		return this.port;
	}
	
	/**
	 * Returns the protocol to which the port listener is assigned.
	 * 
	 * @return The protocol.
	 */
	public Protocol getProtocol() {
		return this.protocol;
	}

}
